package cn.edu.buaa.treehole.dao.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/*
 * @author Zhu Leyan
 * */
public class DbConnection {

    private static final Map<Integer, DbConnection> map = new HashMap<>();

    private static final String DRIVER = "com.mysql.jdbc.driver";
    private final String url;
    private final String user;
    private final String pwd;

    private Connection conn;

    public static DbConnection getInstance(String url, String user, String pwd) {
        if (map.containsKey(Objects.hash(url, user, pwd))) {
            return map.get(Objects.hash(url, user, pwd));
        }
        DbConnection newInstance = new DbConnection(url, user, pwd);
        map.put(Objects.hash(url, user, pwd), newInstance);
        return newInstance;
    }

    /**
     * Constructs a new MySQL database connection manager.
     * The connection is not established, use {@code open} for initializing connection.
     * @param url The url of database.
     * @param user The username for database accessing.
     * @param pwd The corresponding password to {@code user}.
     */
    private DbConnection(String url, String user, String pwd) {
        this.url = url;
        this.user = user;
        this.pwd = pwd;
    }

    /**
     * Retrieves whether this connection has been closed.
     * @return {@code true} if the connection is never opened or has been closed.
     * {@code false} otherwise.
     * @throws SQLException if error occurs while checking the status of connection.
     */
    public boolean isClosed() throws SQLException {
        return conn == null || conn.isClosed();
    }

    /**
     * Open the connection. If the connection has already been established,
     * it will be closed and opened one more time.
     * @return {@code true} if connection is successfully established, otherwise
     * {@code false}.
     */
    public boolean open() {
        try {
            //Class.forName(DRIVER);
            //if (conn != null && !conn.isClosed()) {
            //    conn.close();
            //}
            conn = DriverManager.getConnection(url, user, pwd);
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * Close the connection. If the connection has not been initialized or
     * the connection has already been closed, nothing will happen.
     * @return {@code true} if operation is success, {@code false} if error
     * occurs during the process.
     */
    public boolean close() {
        try {
            if (conn != null && !conn.isClosed()) {
                conn.close();
            }
            return true;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return false;
    }

    /**
     * Get the connection instance, which should have been established
     * using {@code open}.
     * @return The connection instance.
     * @throws SQLException if error occurs while checking the status of connection.
     */
    public Connection getConnection() throws SQLException {
        //if (conn == null || conn.isClosed()) {
        //    return null;
        //}
        //return conn;
        return DriverManager.getConnection(this.url, this.user, this.pwd);
    }
}
